home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / graphics / sfwjpg / src / sfwjpg.c < prev    next >
C/C++ Source or Header  |  1999-06-15  |  11KB  |  392 lines

  1. /*
  2.  * sfwjpg.c
  3.  *
  4.  * Copyright (c) 1997-1999  Everett Lipman
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License
  8.  * as published by the Free Software Foundation; either version 2
  9.  * of the License, or (at your option) any later version.
  10.  * 
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  * 
  16.  * The GNU General Public License is available at
  17.  *
  18.  *    http://www.fsf.org/copyleft/gpl.html
  19.  *
  20.  * Alternatively, you can write to the 
  21.  *
  22.  *    Free Software Foundation, Inc.
  23.  *    59 Temple Place - Suite 330
  24.  *    Boston, MA  02111-1307, USA
  25.  *
  26.  *
  27.  * Revision History:
  28.  *
  29.  *     22 Sep 1997  EAL Completed first version.
  30.  *      9 Jan 1999  EAL Changed to forward scanning for the end of
  31.  *                      JFIF data, as suggested by Bo Lindbergh.
  32.  *      9 May 1999  EAL Unknown markers now result in warning, not
  33.  *                      failure.  Unknown markers will be converted
  34.  *                      to COM (0xfe) marker.  Added code to deal with
  35.  *                      SFW DHT marker (0xa4).  Added output options
  36.  *                      suggested by John Oppenheimer.
  37.  */
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #include <errno.h>
  45.  
  46. #define USCH unsigned char
  47. #define HUFFSIZE 420
  48.  
  49. /*** 420 characters ***/
  50.  
  51. USCH hufftbl[] = {
  52. 0xFF,0xC4,0x01,0xA2,0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,
  53. 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,
  54. 0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,
  55. 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x10,0x00,
  56. 0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D,0x01,
  57. 0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,
  58. 0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,
  59. 0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29,
  60. 0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,
  61. 0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
  62. 0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
  63. 0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,
  64. 0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,
  65. 0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,0xE3,
  66. 0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
  67. 0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,
  68. 0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,
  69. 0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,
  70. 0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,
  71. 0x1A,0x26,0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,
  72. 0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,
  73. 0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,
  74. 0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,
  75. 0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,
  76. 0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,
  77. 0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,
  78. 0xF7,0xF8,0xF9,0xFA
  79. };
  80.  
  81. USCH markertbl[256];
  82.  
  83. int sfw_to_jfif(USCH *sfwstart, USCH *sfwend, char *filename);
  84. USCH *forward_scan(USCH *start, USCH *stop, USCH *goal, int length);
  85. int fix_marker(USCH *marker);
  86. long read_skip_length(USCH *marker);
  87.  
  88. int main(int argc, char **argv)
  89. {
  90.    struct stat filestat;
  91.            int retval;
  92.         size_t sretval, namelen;
  93.           char mesg[256];
  94.           char infilename[256];
  95.           char outfilename[256];
  96.           USCH *filebuf;
  97.           FILE *infile;
  98.  
  99. if ((argc == 1) || (argc > 3))
  100.    {
  101.    fprintf(stderr,"\nusage: sfwjpg inputfile [-|outputfile]\n\n");
  102.    fprintf(stderr,"where inputfile is the .sfw file which\n");
  103.    fprintf(stderr,"will be converted to .jpg (JFIF) format,\n");
  104.    fprintf(stderr,"and outputfile is the name of the resulting\n");
  105.    fprintf(stderr,"file.  - specifies standard output.\n");
  106.    fprintf(stderr,"If no output file is specified, the .sfw in\n");
  107.    fprintf(stderr,"the input file will be replaced with .jpg, and\n");
  108.    fprintf(stderr,"the resulting filename will be used.\n\n");
  109.    exit(1);
  110.    }
  111.  
  112. /*** make input and output filenames *********************************/
  113.  
  114. strncpy(infilename,argv[1],255);
  115. namelen = strlen(infilename);
  116. if ( strcasecmp(infilename+(namelen-4), ".sfw") != 0 )
  117.    {
  118.    strcat(infilename, ".sfw");
  119.    namelen += 4;
  120.    }
  121.  
  122. if (argc == 3)
  123.    {
  124.    if (strcasecmp(argv[2],"-") == 0)
  125.       outfilename[0] = '\0';
  126.    else
  127.       strncpy(outfilename,argv[2],255);
  128.    }
  129. else
  130.    {
  131.    strcpy(outfilename,infilename);
  132.    strcpy(outfilename+(namelen-4),".jpg");
  133.    }
  134.  
  135. /*** read in .sfw file ***********************************************/
  136.  
  137. retval = stat(infilename,&filestat);
  138. if (retval == -1)
  139.    {
  140.    sprintf(mesg,"Error getting status for file '%s'",infilename);
  141.    fprintf(stderr,"\n");
  142.    perror(mesg);
  143.    fprintf(stderr,"\n");
  144.    exit(1);
  145.    }
  146.  
  147. filebuf = (USCH *) malloc( (size_t) filestat.st_size);
  148. if (filebuf == NULL)
  149.    {
  150.    fprintf(stderr,"\n");
  151.    perror("Error allocating memory for filebuf");
  152.    fprintf(stderr,"\n");
  153.    exit(1);
  154.    }
  155.  
  156. infile = fopen(infilename,"rb");
  157. if (infile == NULL)
  158.    {
  159.    sprintf(mesg,"Error opening file '%s'",infilename);
  160.    fprintf(stderr,"\n");
  161.    perror(mesg);
  162.    fprintf(stderr,"\n");
  163.    exit(1);
  164.    }
  165.  
  166. sretval = fread(filebuf, filestat.st_size, 1, infile);
  167. if (sretval == 0)
  168.    {
  169.    sprintf(mesg,"Error reading file '%s'",infilename);
  170.    fprintf(stderr,"\n");
  171.    perror(mesg);
  172.    fprintf(stderr,"\n");
  173.    exit(1);
  174.    }
  175. fclose(infile);
  176.  
  177. retval = sfw_to_jfif(filebuf, filebuf+filestat.st_size-1, outfilename);
  178.  
  179. if (retval != 0)
  180.    {
  181.    fprintf(stderr, "Conversion to %s failed.  Exiting.\n\n",outfilename);
  182.    exit(1);
  183.    }
  184.  
  185. free( (void *) filebuf );
  186. exit(0);
  187. }
  188. /***********************************************************************/
  189. /***********************************************************************/
  190.  
  191. int sfw_to_jfif(USCH *sfwstart, USCH *sfwend, char *filename)
  192. {
  193.    int i, retval, dataflag = 0, huffmanflag = 0;
  194. size_t sretval;
  195.   char mesg[256];
  196.   USCH scanbuf[256];
  197.   USCH *bufpos, *headerstart, *headerend, *dataend;
  198.   FILE *outfile;
  199.  
  200. /*** Initialize lookup table for marker conversions ***/
  201.  
  202. for (i=0;i<256;i++) markertbl[i] = 0x00;
  203.  
  204. markertbl[0xa0] = 0xc0;   /* SOF0 */
  205. markertbl[0xa4] = 0xc4;   /* DHT  */
  206. markertbl[0xc8] = 0xd8;   /* SOI  */
  207. markertbl[0xc9] = 0xd9;   /* EOI  */
  208. markertbl[0xca] = 0xda;   /* SOS  */
  209. markertbl[0xcb] = 0xdb;   /* DQT  */
  210. markertbl[0xd0] = 0xe0;   /* APP0 */
  211.  
  212. /*** Scan for start of JFIF data ***/
  213.  
  214. scanbuf[0] = 0xff;
  215. scanbuf[1] = 0xc8;
  216. scanbuf[2] = 0xff;
  217. scanbuf[3] = 0xd0;
  218. headerstart = forward_scan(sfwstart, sfwend, scanbuf, 4);
  219. if (headerstart == NULL) return(-1);
  220.  
  221. /*** fix SOI and APP0 tags ***/
  222.  
  223. retval = fix_marker(headerstart);
  224. if (retval == -1) return(-1);
  225. retval = fix_marker(headerstart+2);
  226. if (retval == -1) return(-1);
  227.  
  228. /*** fix identifier and version number           ***/
  229. /*** place string "JFIF\0\001\0" in proper place ***/
  230.  
  231. headerstart[6]  = 0x4a;
  232. headerstart[7]  = 0x46;
  233. headerstart[8]  = 0x49;
  234. headerstart[9]  = 0x46;
  235. headerstart[10] = 0x00;
  236. headerstart[11] = 0x01;
  237. headerstart[12] = 0x00;
  238.  
  239. /*** set bufpos to start of next marker ***/
  240.  
  241. bufpos = headerstart + 2;
  242. bufpos += read_skip_length(bufpos); 
  243.  
  244. /*** fix remaining markers ***/
  245.  
  246. while (!dataflag)
  247.    {
  248.    retval = fix_marker(bufpos);
  249.    if (retval == -1) return(-1);
  250.    if (retval == (int)0xc4) huffmanflag = 1;
  251.    if (bufpos[1] == 0xda)
  252.       dataflag = 1;
  253.    else
  254.       bufpos += read_skip_length(bufpos);
  255.    }
  256. headerend = bufpos-1;
  257.  
  258. /*** scan forward for EOI marker ***/
  259.  
  260. scanbuf[0] = 0xff;
  261. scanbuf[1] = 0xc9;
  262. dataend = forward_scan(bufpos, sfwend, scanbuf, 2);
  263. if (dataend == NULL) return(-1);
  264.  
  265. /*** fix EOI marker ***/
  266.  
  267. retval = fix_marker(dataend);
  268. if (retval == -1) return(-1);
  269. dataend ++;
  270.  
  271. /*** open output file ***/
  272.  
  273. if (filename[0] == '\0') 
  274.    outfile = stdout;
  275. else
  276.    outfile = fopen(filename,"wb");
  277.  
  278. if (outfile == NULL)
  279.    {
  280.    if (filename[0] == '\0') strcpy(filename, "standard output");
  281.    sprintf(mesg,"Error opening file '%s'",filename);
  282.    fprintf(stderr,"\n");
  283.    perror(mesg);
  284.    fprintf(stderr,"\n");
  285.    return(-1);
  286.    }
  287.  
  288. /*** write jfif file header ***/
  289.  
  290. sretval = fwrite(headerstart, (headerend-headerstart)+1, 1, outfile);
  291. if (sretval == 0)
  292.    {
  293.    sprintf(mesg,"Error writing file '%s'",filename);
  294.    fprintf(stderr,"\n");
  295.    perror(mesg);
  296.    fprintf(stderr,"\n");
  297.    return(-1);
  298.    }
  299.  
  300. /*** write Huffman table if it is not already there ***/
  301.  
  302. if (!huffmanflag)
  303.    {
  304.    sretval = fwrite(hufftbl, HUFFSIZE, 1, outfile);
  305.    if (sretval == 0)
  306.       {
  307.       sprintf(mesg,"Error writing file '%s'",filename);
  308.       fprintf(stderr,"\n");
  309.       perror(mesg);
  310.       fprintf(stderr,"\n");
  311.       return(-1);
  312.       }
  313.    }
  314.  
  315. /*** write rest of jfif file ***/
  316.  
  317. sretval = fwrite(headerend+1, dataend-headerend, 1, outfile);
  318. if (sretval == 0)
  319.    {
  320.    sprintf(mesg,"Error writing file '%s'",filename);
  321.    fprintf(stderr,"\n");
  322.    perror(mesg);
  323.    fprintf(stderr,"\n");
  324.    return(-1);
  325.    }
  326.  
  327. fclose(outfile);
  328. return(0);
  329. }
  330. /***********************************************************************/
  331.  
  332. USCH *forward_scan(USCH *start, USCH *stop, USCH *goal, int length)
  333. {
  334. USCH *i;
  335. int j, flag;
  336.  
  337. for (i=start; i<stop; i++)
  338.    {
  339.    if (*i != *goal) continue;
  340.    else
  341.       {
  342.       if (length == 1) return(i);
  343.       else
  344.          {
  345.          flag = 1;
  346.          for (j=1; j<length; j++)
  347.             if ( *(i+j) != *(goal+j) )
  348.                {
  349.                flag = 0;
  350.                break;
  351.                }
  352.          if (flag) return(i);
  353.          }
  354.       }
  355.    }
  356. fprintf(stderr,"forward_scan() failed.\n\n");
  357. return(NULL);
  358. }
  359. /***********************************************************************/
  360.  
  361. int fix_marker(USCH *marker)
  362. {
  363. if (marker[0] != 0xFF)
  364.    {
  365.    fprintf(stderr, "fix_marker(): Marker must begin with 0xFF. 0x%02x 0x%02x\n"
  366.                     , marker[0], marker[1]);
  367.    return(-1);
  368.    }
  369. if (markertbl[marker[1]] == 0)
  370.    {
  371.    fprintf(stderr, "\nWARNING: Unknown marker 0x%02x changed to comment.\n\n",
  372.            marker[1]);
  373.    marker[1] = 0xfe;   /* 0xfe is the comment marker */
  374.    }
  375. else
  376.    marker[1] = markertbl[marker[1]];
  377. return((int)marker[1]);
  378. }
  379. /***********************************************************************/
  380.  
  381. long read_skip_length(USCH *marker)
  382. {
  383. long msb,lsb, retval;
  384.  
  385. msb = (long) marker[2];
  386. lsb = (long) marker[3];
  387.  
  388. retval = 256*msb + lsb + 2;
  389. return( retval );
  390. }
  391. /***********************************************************************/
  392.